package com.wingsoft.work.service.impl;

import com.wingsoft.common.core.domain.entity.SysUser;
import com.wingsoft.common.exception.ServiceException;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

import com.wingsoft.common.utils.SecurityUtils;
import com.wingsoft.system.service.impl.SysUserServiceImpl;
import com.wingsoft.work.domain.UserVip;
import com.wingsoft.work.dto.ActivationEntity;
import com.wingsoft.work.vo.UserVipVo;
import org.apache.commons.lang3.ObjectUtils;
import com.wingsoft.common.utils.bean.BeanUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.wingsoft.work.mapper.ActivationMapper;
import com.wingsoft.work.domain.Activation;
import com.wingsoft.work.service.IActivationService;
import com.wingsoft.common.utils.IdGenerator.IdGeneratorFactory;
import com.wingsoft.work.dto.ActivationDto;
import com.wingsoft.work.vo.ActivationVo;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;

import java.util.stream.Collectors;
import java.security.SecureRandom;
import java.util.stream.Stream;

/**
 * 激活码Service业务层处理
 *
 * @author hemj
 * @date 2025-10-20
 */
@Service
public class ActivationServiceImpl extends MPJBaseServiceImpl<ActivationMapper, Activation> implements IActivationService
{
    @Autowired
    private IdGeneratorFactory idGeneratorFactory;
    @Autowired
    private SysUserServiceImpl sysUserService;
    @Autowired
    private UserVipServiceImpl userVipService;


    private static final String CHARACTERS = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
    private static final int CODE_LENGTH = 10;

    public static String generateActivationCodeWithCheck() {
        SecureRandom random = new SecureRandom();
        StringBuilder sb = new StringBuilder(CODE_LENGTH);

        // 生成前7位随机字符
        for (int i = 0; i < CODE_LENGTH - 1; i++) {
            int randomIndex = random.nextInt(CHARACTERS.length());
            sb.append(CHARACTERS.charAt(randomIndex));
        }

        // 添加校验位（简单示例）
        char lastChar = calculateCheckCharacter(sb.toString());
        sb.append(lastChar);

        return sb.toString();
    }

    private static char calculateCheckCharacter(String partialCode) {
        int sum = 0;
        for (char c : partialCode.toCharArray()) {
            sum += c;
        }
        return CHARACTERS.charAt(sum % CHARACTERS.length());
    }

    /**
         * 验证参数
         */
    private void validateData(Activation activation){
    }

    @Transactional
    public void addFast(ActivationDto activationDto) {
        Integer num = activationDto.getNum();
        Integer days = activationDto.getDays();
        if (ObjectUtils.isEmpty(days)){
            days = 30;
        }
        BigDecimal pointNum = activationDto.getPointNum();
        if (ObjectUtils.isEmpty(pointNum)){
            pointNum = BigDecimal.valueOf(100);
        }
        for (Integer i = 0; i < num; i++) {
            boolean isGenera = false;
            do {
                String code = generateActivationCodeWithCheck();
                LambdaQueryWrapper<Activation> activationLambdaQueryWrapper = new LambdaQueryWrapper<>();
                activationLambdaQueryWrapper.eq(Activation::getCode, code);
                if (this.count(activationLambdaQueryWrapper) == 0) {
                    Activation activation = new Activation();
                    activation.setId(idGeneratorFactory.getId(Activation.class));
                    activation.setCreateUserId(SecurityUtils.getUserId());
                    activation.setCode(generateActivationCodeWithCheck());
                    activation.setStatus(1);
                    activation.setDays(days);
                    activation.setPointNum(pointNum);
                    this.save(activation);
                    isGenera = true;
                }
            }while (!isGenera);
        }
    }

    @Transactional
    public void addAdmin(ActivationDto activationDto) {
        if (ObjectUtils.isEmpty(activationDto.getCreateUserId())){
            throw new ServiceException("请选择渠道用户");
        }
        Integer num = activationDto.getNum();
        Integer days = activationDto.getDays();
        if (ObjectUtils.isEmpty(days)){
            days = 30;
        }
        BigDecimal pointNum = activationDto.getPointNum();
        if (ObjectUtils.isEmpty(pointNum)){
            pointNum = BigDecimal.valueOf(100);
        }
        for (Integer i = 0; i < num; i++) {
            boolean isGenera = false;
            do {
                String code = generateActivationCodeWithCheck();
                LambdaQueryWrapper<Activation> activationLambdaQueryWrapper = new LambdaQueryWrapper<>();
                activationLambdaQueryWrapper.eq(Activation::getCode, code);
                if (this.count(activationLambdaQueryWrapper) == 0) {
                    Activation activation = new Activation();
                    activation.setId(idGeneratorFactory.getId(Activation.class));
                    activation.setCreateUserId(activationDto.getCreateUserId());
                    activation.setCode(generateActivationCodeWithCheck());
                    activation.setStatus(1);
                    activation.setDays(days);
                    activation.setPointNum(pointNum);
                    this.save(activation);
                    isGenera = true;
                }
            }while (!isGenera);
        }
    }

    /**
     * 保存数据
     */
    @Transactional(timeout = 3000, isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.REQUIRED)
    public Activation saveCascade(ActivationDto activationDto){
        Activation activation = new Activation();
        BeanUtils.copyProperties(activationDto,activation);
        validateData(activation);
        activation.setId(idGeneratorFactory.getId(Activation.class.getSimpleName()));
        this.save(activation);
        return activation;
    }
    /**
     * 编辑数据
     */
    @Transactional(timeout = 3000, isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.REQUIRED)
    public Activation updateCascade(ActivationDto activationDto){
        Activation activation = this.getById(activationDto.getId());;
        BeanUtils.copyPropertiesIgnoreNull(activationDto,activation);
        validateData(activation);
        this.updateById(activation);
        return activation;
    }

    /**
     * 初始化查询条件
     */
    public MPJLambdaWrapper<Activation> initQueryWrapper(ActivationDto activationDto){
        MPJLambdaWrapper<Activation> queryWrapper = new MPJLambdaWrapper<>();
        if (!ObjectUtils.isEmpty(activationDto.getCreateUserId())) {
            queryWrapper.eq(Activation::getCreateUserId, activationDto.getCreateUserId());
        }
        if (!ObjectUtils.isEmpty(activationDto.getCode())) {
            queryWrapper.eq(Activation::getCode, activationDto.getCode());
        }
        if (!ObjectUtils.isEmpty(activationDto.getStatus())) {
            queryWrapper.eq(Activation::getStatus, activationDto.getStatus());
        }
        if (!ObjectUtils.isEmpty(activationDto.getDays())) {
            queryWrapper.eq(Activation::getDays, activationDto.getDays());
        }
        if (!ObjectUtils.isEmpty(activationDto.getUsedTime())) {
            queryWrapper.eq(Activation::getUsedTime, activationDto.getUsedTime());
        }
        if (!ObjectUtils.isEmpty(activationDto.getUserId())) {
            queryWrapper.eq(Activation::getUserId, activationDto.getUserId());
        }
        queryWrapper.orderByDesc(Activation::getId);
        return queryWrapper;
    }

    /**
     * list查询
     */
    public List<ActivationVo> queryList(ActivationDto activationDto) {
        List<Activation> activations = this.selectJoinList(Activation.class,initQueryWrapper(activationDto));
        if (ObjectUtils.isEmpty(activations)) {
            return new ArrayList<>();
        }
        List<Long> allUserIds = activations.stream()
                .flatMap(activation -> Stream.of(activation.getUserId(), activation.getCreateUserId()))
                .filter(Objects::nonNull) // 可选：过滤掉可能为null的值
                .distinct() // 可选：去除重复的ID
                .collect(Collectors.toList());
        List<SysUser> sysUsers = sysUserService.listByIds(allUserIds);
        Map<Long, SysUser> sysUserMap = sysUsers.stream()
                .collect(Collectors.toMap(
                        SysUser::getUserId, // 指定 Map 的键为用户的 ID
                        sysUser -> sysUser // 指定 Map 的值为用户对象本身
                ));

        List<ActivationVo> vos = new ArrayList<>();
        for (Activation activation:activations) {
            ActivationVo activationVo = new ActivationVo();
            BeanUtils.copyProperties(activation,activationVo);
            if (!ObjectUtils.isEmpty(activation.getCreateUserId())){
                SysUser sysUser = sysUserMap.get(activation.getCreateUserId());
                if (!ObjectUtils.isEmpty(sysUser)) {
                    activationVo.setCreateUserName(sysUser.getNickName());
                }
            }
            if (!ObjectUtils.isEmpty(activation.getUserId())){
                SysUser sysUser = sysUserMap.get(activation.getUserId());
                if (!ObjectUtils.isEmpty(sysUser)) {
                    activationVo.setUserName(sysUser.getNickName());
                }
            }
            vos.add(activationVo);
        }
        return vos;
    }

    /**
     * 统计
     */
    public long countList(ActivationDto activationDto) {
        return this.count(initQueryWrapper(activationDto));
    }

    /**
     * 获取单个数据
     */
    public ActivationVo getOneById(Long id){
        Activation activation = this.getById(id);
        ActivationVo activationVo = new ActivationVo();
        BeanUtils.copyProperties(activation,activationVo);
        return activationVo;
    }

    /**
     * 删除数据
     * @param ids
     */
    @Transactional(timeout = 3000, isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.REQUIRED)
    public void removeByIdList(List<Long> ids) {
        this.removeByIds(ids);
    }


    @Transactional
    public void active(ActivationEntity activationEntity) {
        if (ObjectUtils.isEmpty(activationEntity.getCode())) {
            throw new ServiceException("激活码必填！");
        }
        LambdaQueryWrapper<Activation> activationLambdaQueryWrapper = new LambdaQueryWrapper<>();
        activationLambdaQueryWrapper.eq(Activation::getCode, activationEntity.getCode());
        Activation activation = this.getOne(activationLambdaQueryWrapper,false);
        if (ObjectUtils.isEmpty(activation)) {
            throw new ServiceException("激活码错误！");
        }
        if (activation.getStatus() != 1){
            throw new ServiceException("激活码已失效！");
        }
        Long userId = SecurityUtils.getUserId();
        LambdaQueryWrapper<UserVip> vipWrapper = new LambdaQueryWrapper<>();
        vipWrapper.eq(UserVip::getUserId, userId);
        UserVip userVip = userVipService.getOne(vipWrapper,false);
        if (ObjectUtils.isEmpty(userVip)) {
            userVip = new UserVip();
            userVip.setId(idGeneratorFactory.getId(UserVip.class));
            userVip.setUserId(userId);
            userVip.setCreateTime(new Date());
            userVip.setCreateBy(SecurityUtils.getUsername());
            userVip.setPointNum(BigDecimal.ZERO);
            userVip.setExpireTime(LocalDateTime.now());
            userVip.setTotalPointNum(BigDecimal.ZERO);
            userVip.setStatus(1);
        }
        if (userVip.getStatus() == 2){
            //已失效激活
            userVip.setExpireTime(LocalDateTime.now().plusDays(activation.getDays()));
        }else {
            userVip.setExpireTime(userVip.getExpireTime().plusDays(activation.getDays()));
        }
        userVip.setPointNum(userVip.getPointNum().add(activation.getPointNum()));
        userVip.setTotalPointNum(userVip.getTotalPointNum().add(activation.getPointNum()));

        userVipService.saveOrUpdate(userVip);

        activation.setStatus(2);
        activation.setUserId(userId);
        activation.setUsedTime(LocalDateTime.now());
        this.updateById(activation);
    }


}
